<?php
namespace Ipaddress;
header("content-type:text/html;charset=GB2312");

//*QQ IP数据库 纯真版20120320
//文件头 [第一条索引的偏移量 (4byte)] + [最后一条索引的偏移地址 (4byte)]     8字节
//记录区 [结束ip (4byte)] + [地区1] + [地区2]                                                             4字节+不定长 
//索引区 [开始ip (4byte)] + [指向记录区的偏移地址 (3byte)]                                  7字节
//*
class Ipaddress {
	var $fp;
	var $firstip;  //第一条ip索引的偏移地址
	var $lastip;   //最后一条ip索引的偏移地址
	var $totalip;  //总ip数
	//*
	//构造函数,初始化一些变量
	//$datfile 的值为纯真IP数据库的名子,可自行修改.
	//*
	function __construct(){
		  $datfile=dirname(__FILE__).'/qqwry.dat';
		  
		  $this->fp=fopen($datfile,'rb');   //二制方式打开
		  $this->firstip = $this->get4b(); //第一条ip索引的绝对偏移地址
		  $this->lastip = $this->get4b();  //最后一条ip索引的绝对偏移地址
		  $this->totalip =($this->lastip - $this->firstip)/7 ; //ip总数 索引区是定长的7个字节,在此要除以7, 
		  register_shutdown_function(array($this,"closefp"));  //为了兼容php5以下版本,本类没有用析构函数,自动关闭ip库.
	}
	//*
	//关闭ip库
	//*
	function closefp(){
		fclose($this->fp);
	}
	//*
	//读取4个字节并将解压成long的长模式
	//*
	function get4b(){
		$str=unpack("V",fread($this->fp,4));
		return $str[1];
	}
	//*
	//读取重定向了的偏移地址
	//*
	function getoffset(){
		$str=unpack("V",fread($this->fp,3).chr(0));
		return $str[1];
	}
	//*
	//读取ip的详细地址信息
	//*
	function getstr(){
		$str="";
		$split=fread($this->fp,1);
		while (ord($split)!=0) {
			$str .=$split;
			$split=fread($this->fp,1);
		}
		return $str;
	}
	//*
	//将ip通过ip2long转成ipv4的互联网地址,再将他压缩成big-endian字节序
	//用来和索引区内的ip地址做比较
	//*
	function iptoint($ip){
		return pack("N",intval(ip2long($ip))); 
	}
	//*
	//获取客户端ip地址
	//注意:如果你想要把ip记录到服务器上,请在写库时先检查一下ip的数据是否安全.
	//*
	function getIp() {
		static $realip = null;
		if ($realip !== null){
			return $realip;
		}
		if (isset($_SERVER)){
			if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])){
				$arr = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
				foreach ($arr AS $ip){
					$ip = trim($ip);
					if ($ip != 'unknown'){
						$realip = $ip;
						break;
					}
				}
			}elseif (isset($_SERVER['HTTP_CLIENT_IP'])){
				$realip = $_SERVER['HTTP_CLIENT_IP'];
			}else{
				if (isset($_SERVER['REMOTE_ADDR'])){
					$realip = $_SERVER['REMOTE_ADDR'];
				}else{
					$realip = '0.0.0.0';
				}
			}
		}
		else{
			if (getenv('HTTP_X_FORWARDED_FOR')){
				$realip = getenv('HTTP_X_FORWARDED_FOR');
			}elseif (getenv('HTTP_CLIENT_IP')){
				$realip = getenv('HTTP_CLIENT_IP');
			}else{
				$realip = getenv('REMOTE_ADDR');
			}
		}
		preg_match("/[\d\.]{7,15}/", $realip, $onlineip);
		$realip = !empty($onlineip[0]) ? $onlineip[0] : '0.0.0.0';
		return $realip;
	 
	}
	//*
	//获取地址信息
	//*
	function readaddress(){
		$now_offset=ftell($this->fp); //得到当前的指针位址
		$flag=$this->getflag();
		switch (ord($flag)){
			 case 0:
		   $address="";
		break;
		case 1:
		case 2:
		   fseek($this->fp,$this->getoffset());
		$address=$this->getstr();
		break;
		default:
		   fseek($this->fp,$now_offset);
		   $address=$this->getstr();
		break;
		}
		return $address;
	}
	//*
	//获取标志1或2
	//用来确定地址是否重定向了.
	//*
	function getflag(){
		return fread($this->fp,1);
	}
	//*
	//用二分查找法在索引区内搜索ip
	//* www.phperz.com 
	function searchip($ip){
		$ip=gethostbyname($ip);     //将域名转成ip
		$ip_offset["ip"]=$ip;
		$ip=$this->iptoint($ip);    //将ip转换成长整型
		$firstip=0;                 //搜索的上边界
		$lastip=$this->totalip;     //搜索的下边界
		$ipoffset=$this->lastip;    //初始化为最后一条ip地址的偏移地址
		while ($firstip <= $lastip){
		$i=floor(($firstip + $lastip) / 2);          //计算近似中间记录 floor函数记算给定浮点数小的最大整数,说白了就是四舍五也舍
		fseek($this->fp,$this->firstip + $i * 7);    //定位指针到中间记录
		$startip=strrev(fread($this->fp,4));       //读取当前索引区内的开始ip地址,并将其little-endian的字节序转换成big-endian的字节序 
		if ($ip < $startip) {
		$lastip=$i - 1;
		}else {
			fseek($this->fp,$this->getoffset());
			$endip=strrev(fread($this->fp,4));
			if ($ip > $endip){
			   $firstip=$i + 1;
			}else {
			   $ip_offset["offset"]=$this->firstip + $i * 7;
			   break;
			}
		}
	  }
	  return $ip_offset;
	}
	//*
	//获取ip地址详细信息
	//*
	function getaddress($ip){
		  $ip_offset=$this->searchip($ip);  //获取ip 在索引区内的绝对编移地址
		  $ipoffset=$ip_offset["offset"];
		  $address["ip"]=$ip_offset["ip"];
		  fseek($this->fp,$ipoffset);      //定位到索引区
		  $address["startip"]=long2ip($this->get4b()); //索引区内的开始ip 地址 php程序员站 
		  $address_offset=$this->getoffset();            //获取索引区内ip在ip记录区内的偏移地址
		  fseek($this->fp,$address_offset);            //定位到记录区内
		  $address["endip"]=long2ip($this->get4b());   //记录区内的结束ip 地址
		  $flag=$this->getflag();                      //读取标志字节
		
		  switch (ord($flag)) {
			case 1:  //地区1地区2都重定向
			$address_offset=$this->getoffset();   //读取重定向地址
			fseek($this->fp,$address_offset);     //定位指针到重定向的地址
			$flag=$this->getflag();               //读取标志字节 
			switch (ord($flag)) {
			case 2:  //地区1又一次重定向,
			fseek($this->fp,$this->getoffset());
			$address["address"]=$this->getstr();

			fseek($this->fp,$address_offset+4);      //跳4个字节
			$address["provider"]=$this->readaddress();  //地区2有可能重定向,有可能没有
			break;
			default: //地区1,地区2都没有重定向
			fseek($this->fp,$address_offset);        //定位指针到重定向的地址
			$address["address"]=$this->getstr();
			$address["provider"]=$this->readaddress();
			break;
			}
			break;
			case 2: //地区1重定向 地区2没有重定向 phperz~com 
			$address1_offset=$this->getoffset();   //读取重定向地址
			fseek($this->fp,$address1_offset);  
			$address["address"]=$this->getstr();
			fseek($this->fp,$address_offset+8);
			$address["provider"]=$this->readaddress();
			break;
			default: //地区1地区2都没有重定向
			fseek($this->fp,$address_offset+4);
			$address["address"]=$this->getstr();
			$address["provider"]=$this->readaddress();
			break;
		  }
		  //*过滤一些无用数据
		  if (strpos($address["address"],"CZ88.NET")!=false){
			  $address["address"]="未知";
		  }
		  if (strpos($address["provider"],"CZ88.NET")!=false){
			  $address["provider"]=" "; 
		  }
		
		  $address['address'] = $this->toUTF8( $address['address'] );
		  $address['provider'] = $this->toUTF8( $address['provider'] );
		  $address["exp_address"]=$this->exp_address($address['address']);
		  return $address;
	 }

	 public function toUTF8($str)
    {
        
        $encoding = mb_detect_encoding($str, 'GB2312');
        if ( $encoding !==false ) {
            $str = iconv('GB2312','UTF-8//IGNORE', $str);    
        }

        return $str;

	}
	
	//分开获得省份和市区
	public function exp_address($str){
		$res=array();
		$Area = model('Area');

		/* 特别行政区 */
		$province=stripos($str,"香港");
		
		
		if($province!==false){
			
			$res['province']['name']="香港";
			//获得code
			$province_info=$Area->fetchAreaInfo(["type"=>"province","name"=>$res['province']['name']]);
			
			if($province_info["Code"]==200){
				$res['province']['code']=$province_info["Data"]['code'];
			}else{
				$res['province']['code']="";
			}
			return $res;
		}

		$province=stripos($str,"澳门");
		if($province!==false){
			$res['province']['name']="澳门";
			//获得code
			$province_info=$Area->fetchAreaInfo(["type"=>"province","name"=>$res['province']['name']]);
			
			if($province_info["Code"]==200){
				$res['province']['code']=$province_info["Data"]['code'];
			}else{
				$res['province']['code']="";
			}
			return $res;
		}
		/* 特别行政区 end*/

		/* 省 */
		$province=stripos($str,"省");
		

		if($province){
			$arr=explode("省",$str);
			$res['province']['name']=$arr[0];
			//获得code
			$province_info=$Area->fetchAreaInfo(["type"=>"province","name"=>$res['province']['name']]);
			
			if($province_info["Code"]==200){
				$res['province']['code']=$province_info["Data"]['code'];
			}else{
				$res['province']['code']="";
			}

			//再进行切割市
			$province1=stripos($str,"市");

			if($province1){
				
				$arr[1]=explode("市",$arr[1])[0];
				$res['city']['name']=$arr[1];
				//获得code
				$city_info=$Area->fetchAreaInfo(["type"=>"city","name"=>$res['city']['name']]);
				
				if($city_info["Code"]==200){
					$res['city']['code']=$city_info["Data"]['code'];
				}else{
					$res['city']['code']="";
				}
			}
			

			
        
			return $res;
		}
		
		/* 省 end */

		

		/* 自治区 */
		$zizhi_arr=["内蒙古","广西","西藏","宁夏","新疆"];
		foreach ($zizhi_arr as $value) {
			$province=stripos($str,$value);
			// $arr1[$value]=$province;
			if($province!==false){
				
			
				$res['province']['name']=$value;
				//获得code
				$province_info=$Area->fetchAreaInfo(["type"=>"province","name"=>$res['province']['name']]);
				
				if($province_info["Code"]==200){
					$res['province']['code']=$province_info["Data"]['code'];
				}else{
					$res['province']['code']="";
				}

				$res['city']['name']=str_replace($value,"",$str);
				$res['city']['name']=explode("市",$res['city']['name'])[0];
				//获得code
				$city_info=$Area->fetchAreaInfo(["type"=>"city","name"=>$res['city']['name']]);
										
				if($city_info["Code"]==200){
					$res['city']['code']=$city_info["Data"]['code'];
				}else{
					$res['city']['code']="";
				}

				return $res;
			}
		}
	
		/* 自治区 end */

		/* 直辖市  */
		$province=stripos($str,"市");
		if($province){
			$arr=explode("市",$str);
			$res['province']['name']=$arr[0];
			$res['city']['name']="0";//如果city name为0则表示没有
			
			
			//获得code
			$province_info=$Area->fetchAreaInfo(["type"=>"province","name"=>$res['province']['name']]);
			
			if($province_info["Code"]==200){
				$res['province']['code']=$province_info["Data"]['code'];
			}else{
				$res['province']['code']="";
			}
			
			return $res;
		}
		/* 直辖市 end */


		
		return $res;
	}
} 
